// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ConfigurationField.cs" company="Open Trader">
//   Copyright (c) David Denis (david.denis@systemathics.com)
// </copyright>
// <summary>
//   |  Open Trader - The Open Source Systematic Trading Platform
//   |
//   |  This program is free software: you can redistribute it and/or modify
//   |  it under the terms of the GNU General Public License as published by
//   |  the Free Software Foundation, either version 2 of the License, or
//   |  (at your option) any later version.
//   |
//   |  This program is distributed in the hope that it will be useful,
//   |  but WITHOUT ANY WARRANTY; without even the implied warranty of
//   |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//   |  GNU General Public License for more details.
//   |
//   |  You should have received a copy of the GNU General Public License
//   |  along with this program.  If not, see http://www.gnu.org/licenses
//   |
//   |  Up to date informations about Open Trader can be found at :
//   |    http://opentrader.org
//   |    http://opentrader.codeplex.com
//   |
//   |  For professional services, please visit us at :
//   |    http://www.systemathics.com
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Org.OpenTrader.Framework.LiveObjects
{
    #region Using Directives

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;

    using Org.OpenTrader.Framework.LiveObjects.Interfaces;

    #endregion

    /// <summary>
    /// The attribute resource.
    /// </summary>
    [Serializable]
    public abstract class ConfigurationField : IFlatFileExportImport
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ConfigurationField"/> class.
        /// </summary>
        /// <param name="mandatory">
        /// The mandatory.
        /// </param>
        protected ConfigurationField(bool mandatory)
        {
            this.IsMandatory = mandatory;
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets Contents.
        /// </summary>
        public abstract object Contents { get; set; }

        /// <summary>
        /// Gets a value indicating whether IsMandatory.
        /// </summary>
        public bool IsMandatory { get; private set; }

        /// <summary>
        /// Gets a value indicating whether IsSet.
        /// </summary>
        public abstract bool IsSet { get; }

        #endregion

        #region Operators

        /// <summary>
        /// The op_ implicit.
        /// </summary>
        /// <param name="f">
        /// The f.
        /// </param>
        /// <returns>
        /// </returns>
        public static implicit operator string(ConfigurationField f)
        {
            return (string)f.Contents;
        }

        /// <summary>
        /// The op_ implicit.
        /// </summary>
        /// <param name="f">
        /// The f.
        /// </param>
        /// <returns>
        /// </returns>
        public static implicit operator int(ConfigurationField f)
        {
            return (int)f.Contents;
        }

        /// <summary>
        /// The op_ implicit.
        /// </summary>
        /// <param name="f">
        /// The f.
        /// </param>
        /// <returns>
        /// </returns>
        public static implicit operator double(ConfigurationField f)
        {
            return (double)f.Contents;
        }

        /// <summary>
        /// The op_ implicit.
        /// </summary>
        /// <param name="f">
        /// The f.
        /// </param>
        /// <returns>
        /// </returns>
        public static implicit operator float(ConfigurationField f)
        {
            return (float)f.Contents;
        }

        /// <summary>
        /// The op_ implicit.
        /// </summary>
        /// <param name="f">
        /// The f.
        /// </param>
        /// <returns>
        /// </returns>
        public static implicit operator bool(ConfigurationField f)
        {
            return (bool)f.Contents;
        }

        /// <summary>
        /// The op_ implicit.
        /// </summary>
        /// <param name="f">
        /// The f.
        /// </param>
        /// <returns>
        /// </returns>
        public static implicit operator Framework.Table(ConfigurationField f)
        {
            return (f as Table).Contents as Framework.Table;
        }

        /// <summary>
        /// The op_ implicit.
        /// </summary>
        /// <param name="f">
        /// The f.
        /// </param>
        /// <returns>
        /// </returns>
        public static implicit operator byte[](ConfigurationField f)
        {
            return (f as File).Contents as byte[];
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// The unset.
        /// </summary>
        public abstract void Unset();

        #endregion

        #region Implemented Interfaces

        #region IFlatFileExportImport

        /// <summary>
        /// The de serialize.
        /// </summary>
        /// <param name="reader">
        /// The reader.
        /// </param>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <returns>
        /// </returns>
        public abstract Status DeSerialize(StreamReader reader, ISerializationContext context);

        /// <summary>
        /// The serialize.
        /// </summary>
        /// <param name="writer">
        /// The writer.
        /// </param>
        /// <param name="context">
        /// The context.
        /// </param>
        /// <returns>
        /// </returns>
        public abstract Status Serialize(StreamWriter writer, ISerializationContext context);

        #endregion

        #endregion

        /// <summary>
        /// The bool.
        /// </summary>
        [Serializable]
        public class Bool : ConfigurationField
        {
            #region Constants and Fields

            /// <summary>
            /// The identity.
            /// </summary>
            private static readonly Identity Identity = Identity.Create(System.Reflection.MethodBase.GetCurrentMethod());

            /// <summary>
            /// The contents.
            /// </summary>
            private bool? contents;

            #endregion

            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="Bool"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            public Bool(bool mandatory)
                : base(mandatory)
            {
                this.contents = new bool?();
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="Bool"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            /// <param name="b">
            /// The b.
            /// </param>
            public Bool(bool mandatory, bool b)
                : base(mandatory)
            {
                this.contents = new bool?(b);
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets or sets Contents.
            /// </summary>
            public override object Contents
            {
                get
                {
                    return this.contents;
                }

                set
                {
                    if (value is bool?)
                    {
                        this.contents = new bool?((bool)value);
                    }
                    else if (this.IsMandatory)
                    {
                        throw new Exception("Field is mandatory");
                    }
                    else
                    {
                        this.Unset();
                    }
                }
            }

            /// <summary>
            /// Gets a value indicating whether IsSet.
            /// </summary>
            public override bool IsSet
            {
                get
                {
                    return (this.Contents as bool?).HasValue;
                }
            }

            #endregion

            #region Public Methods

            /// <summary>
            /// The de serialize.
            /// </summary>
            /// <param name="reader">
            /// The reader.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            public override Status DeSerialize(StreamReader reader, ISerializationContext context)
            {
                var valueString = reader.ReadLine();
                if (valueString == null)
                {
                    valueString = Constants.NotSet;
                }

                if (valueString.Equals(Constants.NotSet))
                {
                    this.Contents = new bool?();
                }
                else
                {
                    this.Contents = new bool?(bool.Parse(valueString));
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The serialize.
            /// </summary>
            /// <param name="writer">
            /// The writer.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            /// <exception cref="NotImplementedException">
            /// </exception>
            public override Status Serialize(StreamWriter writer, ISerializationContext context)
            {
                if (this.IsSet)
                {
                    writer.WriteLine(this.Contents.ToString());
                }
                else
                {
                    writer.WriteLine(Constants.NotSet);
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The to string.
            /// </summary>
            /// <returns>
            /// The to string.
            /// </returns>
            public override string ToString()
            {
                if (!this.IsSet)
                {
                    return Constants.NotSet;
                }

                return this.Contents.ToString();
            }

            /// <summary>
            /// The unset.
            /// </summary>
            public override void Unset()
            {
                if (! this.IsMandatory)
                {
                    this.contents = new bool?();
                }
            }

            #endregion
        }

        /// <summary>
        /// The double.
        /// </summary>
        [Serializable]
        public class Decimal : ConfigurationField
        {
            #region Constants and Fields

            /// <summary>
            /// The identity.
            /// </summary>
            private static readonly Identity Identity = Identity.Create(System.Reflection.MethodBase.GetCurrentMethod());

            /// <summary>
            /// The contents.
            /// </summary>
            private double? contents;

            #endregion

            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="Decimal"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            public Decimal(bool mandatory)
                : base(mandatory)
            {
                this.contents = new double?();
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="Decimal"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            /// <param name="d">
            /// The d.
            /// </param>
            public Decimal(bool mandatory, double d)
                : base(mandatory)
            {
                this.contents = new double?(d);
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets or sets Contents.
            /// </summary>
            public override object Contents
            {
                get
                {
                    return this.contents;
                }

                set
                {
                    if (value is double?)
                    {
                        this.contents = new double?((double)value);
                    }
                    else if (this.IsMandatory)
                    {
                        throw new Exception("Field is mandatory");
                    }
                    else
                    {
                        this.Unset();
                    }
                }
            }

            /// <summary>
            /// Gets a value indicating whether IsSet.
            /// </summary>
            public override bool IsSet
            {
                get
                {
                    return (this.Contents as double?).HasValue;
                }
            }

            #endregion

            #region Public Methods

            /// <summary>
            /// The de serialize.
            /// </summary>
            /// <param name="reader">
            /// The reader.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            public override Status DeSerialize(StreamReader reader, ISerializationContext context)
            {
                var valueString = reader.ReadLine();
                if (valueString == null)
                {
                    valueString = Constants.NotSet;
                }

                if (valueString.Equals(Constants.NotSet))
                {
                    this.Contents = new double?();
                }
                else
                {
                    this.Contents = new double?(double.Parse(valueString, Constants.CultureInfo));
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The serialize.
            /// </summary>
            /// <param name="writer">
            /// The writer.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            /// <exception cref="NotImplementedException">
            /// </exception>
            public override Status Serialize(StreamWriter writer, ISerializationContext context)
            {
                if (this.IsSet)
                {
                    writer.WriteLine(this.Contents.ToString());
                }
                else
                {
                    writer.WriteLine(Constants.NotSet);
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The to string.
            /// </summary>
            /// <returns>
            /// The to string.
            /// </returns>
            public override string ToString()
            {
                if (!this.IsSet)
                {
                    return Constants.NotSet;
                }

                return this.Contents.ToString();
            }

            /// <summary>
            /// The unset.
            /// </summary>
            public override void Unset()
            {
                if (!this.IsMandatory)
                {
                    this.contents = new double?();
                }
            }

            #endregion
        }

        /// <summary>
        /// The enum.
        /// </summary>
        [Serializable]
        public class Enum : ConfigurationField
        {
            #region Constants and Fields

            /// <summary>
            /// The identity.
            /// </summary>
            private static readonly Identity Identity = Identity.Create(System.Reflection.MethodBase.GetCurrentMethod());

            /// <summary>
            /// The contents.
            /// </summary>
            private string contents;

            #endregion

            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="Enum"/> class. 
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            /// <param name="className">
            /// The class name.
            /// </param>
            /// <param name="value">
            /// The value.
            /// </param>
            /// <param name="possibleValues">
            /// The possible values.
            /// </param>
            public Enum(bool mandatory, string className, string value, string[] possibleValues)
                : base(mandatory)
            {
                this.ClassName = className;
                this.contents = value;
                this.PossibleValues = possibleValues;
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets ClassName.
            /// </summary>
            public string ClassName { get; private set; }

            /// <summary>
            /// Gets or sets Contents.
            /// </summary>
            public override object Contents
            {
                get
                {
                    return this.contents;
                }

                set
                {
                    if (value is string)
                    {
                        var isPresent = from e in this.PossibleValues where e.Equals(value) select e;
                        if (isPresent.Count() > 0)
                        {
                            this.contents = (string)value;
                        }
                        else
                        {
                            throw new Exception(string.Format("{0} is not a valid value for {1}", value, this.ClassName));
                        }
                    }
                    else if (this.IsMandatory)
                    {
                        throw new Exception("Field is mandatory");
                    }
                    else
                    {
                        this.Unset();
                    }
                }
            }

            /// <summary>
            /// Gets a value indicating whether IsSet.
            /// </summary>
            public override bool IsSet
            {
                get
                {
                    return this.Contents != null;
                }
            }

            /// <summary>
            /// Gets PossibleValues.
            /// </summary>
            public string[] PossibleValues { get; private set; }

            #endregion

            #region Public Methods

            /// <summary>
            /// The as.
            /// </summary>
            /// <param name="o">
            /// The o.
            /// </param>
            /// <typeparam name="T">
            /// </typeparam>
            /// <returns>
            /// </returns>
            public static T As<T>(object o)
            {
                var safe = o as Enum;
                if (safe == null)
                {
                    return default(T);
                }

                if (!safe.IsSet)
                {
                    return default(T);
                }

                return (T)System.Enum.Parse(typeof(T), safe.Contents.ToString());
            }

            /// <summary>
            /// The de serialize.
            /// </summary>
            /// <param name="reader">
            /// The reader.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            public override Status DeSerialize(StreamReader reader, ISerializationContext context)
            {
                var valueString = reader.ReadLine();
                if (valueString == null)
                {
                    valueString = Constants.NotSet;
                }

                if (valueString.Equals(Constants.NotSet))
                {
                    this.Contents = null;
                }
                else
                {
                    this.Contents = valueString;
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The serialize.
            /// </summary>
            /// <param name="writer">
            /// The writer.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            /// <exception cref="NotImplementedException">
            /// </exception>
            public override Status Serialize(StreamWriter writer, ISerializationContext context)
            {
                if (this.IsSet)
                {
                    writer.WriteLine(this.Contents);
                }
                else
                {
                    writer.WriteLine(Constants.NotSet);
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The to string.
            /// </summary>
            /// <returns>
            /// The to string.
            /// </returns>
            public override string ToString()
            {
                if (!this.IsSet)
                {
                    return Constants.NotSet;
                }

                return this.Contents.ToString();
            }

            /// <summary>
            /// The unset.
            /// </summary>
            public override void Unset()
            {
                if (!this.IsMandatory)
                {
                    this.contents = null;
                }
            }

            #endregion
        }

        /// <summary>
        /// The attribute resource.
        /// </summary>
        [Serializable]
        public class File : BinaryConfigurationField
        {
            #region Constants and Fields

            /// <summary>
            /// The identity.
            /// </summary>
            private static readonly Identity Identity = Identity.Create(System.Reflection.MethodBase.GetCurrentMethod());

            /// <summary>
            /// The contents.
            /// </summary>
            private byte[] contents;

            #endregion

            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="File"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            public File(bool mandatory)
                : base(mandatory)
            {
                if (this.IsMandatory)
                {
                    this.contents = new byte[] { };
                    this.Name = "File.Empty";
                }
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets or sets Contents.
            /// </summary>
            public override object Contents
            {
                get
                {
                    return this.contents;
                }

                set
                {
                    if (value is byte[])
                    {
                        this.contents = (byte[])value;
                    }
                    else if (this.IsMandatory)
                    {
                        throw new Exception("Field is mandatory");
                    }
                    else
                    {
                        this.Unset();
                    }
                }
            }

            /// <summary>
            /// Gets a value indicating whether IsSet.
            /// </summary>
            public override bool IsSet
            {
                get
                {
                    return this.Contents != null;
                }
            }

            #endregion

            #region Public Methods

            /// <summary>
            /// The de serialize.
            /// </summary>
            /// <param name="reader">
            /// The reader.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            public override Status DeSerialize(StreamReader reader, ISerializationContext context)
            {
                var fileName = reader.ReadLine();
                if (fileName.Equals(Constants.NotSet))
                {
                    this.Name = null;
                    this.contents = null;
                    return Status.Success(Identity);
                }

                if (context.WorkingDirectory != null)
                {
                    // Non null working directory means reading from file
                    context.BinaryContents[fileName] = System.IO.File.ReadAllBytes(string.Format(@"{0}\{1}", context.WorkingDirectory, fileName));
                }
                else
                {
                    // Null working directory means reading from database, thus context.BinaryContents[fileName] should be ready
                }

                this.Name = fileName;
                this.Contents = context.BinaryContents[fileName];
                return Status.Success(Identity);
            }

            /// <summary>
            /// The serialize.
            /// </summary>
            /// <param name="writer">
            /// The writer.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            public override Status Serialize(StreamWriter writer, ISerializationContext context)
            {
                if (this.IsSet)
                {
                    context.BinaryContents[this.Name] = (byte[])this.Contents;
                    writer.WriteLine(this.Name);
                }
                else
                {
                    writer.WriteLine(Constants.NotSet);
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The to string.
            /// </summary>
            /// <returns>
            /// The to string.
            /// </returns>
            public override string ToString()
            {
                if (!this.IsSet)
                {
                    return Constants.NotSet;
                }

                var contents = (byte[])this.Contents;
                return string.Format("{0} (File, size={1} bytes)", this.Name, contents.Length);
            }

            /// <summary>
            /// The unset.
            /// </summary>
            public override void Unset()
            {
                if (!this.IsMandatory)
                {
                    this.contents = null;
                }
            }

            #endregion
        }

        /// <summary>
        /// The int.
        /// </summary>
        [Serializable]
        public class Int : ConfigurationField
        {
            #region Constants and Fields

            /// <summary>
            /// The identity.
            /// </summary>
            private static readonly Identity Identity = Identity.Create(System.Reflection.MethodBase.GetCurrentMethod());

            /// <summary>
            /// The contents.
            /// </summary>
            private int? contents;

            #endregion

            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="Int"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            public Int(bool mandatory)
                : base(mandatory)
            {
                this.contents = new int?();
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="Int"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            /// <param name="i">
            /// The i.
            /// </param>
            public Int(bool mandatory, int i)
                : base(mandatory)
            {
                this.contents = new int?(i);
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets or sets Contents.
            /// </summary>
            public override object Contents
            {
                get
                {
                    return this.contents;
                }

                set
                {
                    if (value is int?)
                    {
                        this.contents = new int?((int)value);
                    }
                    else if (this.IsMandatory)
                    {
                        throw new Exception("Field is mandatory");
                    }
                    else
                    {
                        this.Unset();
                    }
                }
            }

            /// <summary>
            /// Gets a value indicating whether IsSet.
            /// </summary>
            public override bool IsSet
            {
                get
                {
                    return (this.Contents as int?).HasValue;
                }
            }

            #endregion

            #region Public Methods

            /// <summary>
            /// The de serialize.
            /// </summary>
            /// <param name="reader">
            /// The reader.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            public override Status DeSerialize(StreamReader reader, ISerializationContext context)
            {
                var valueString = reader.ReadLine();
                if (valueString == null)
                {
                    valueString = Constants.NotSet;
                }

                if (valueString.Equals(Constants.NotSet))
                {
                    this.Contents = new int?();
                }
                else
                {
                    this.Contents = new int?(int.Parse(valueString, Constants.CultureInfo));
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The serialize.
            /// </summary>
            /// <param name="writer">
            /// The writer.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            /// <exception cref="NotImplementedException">
            /// </exception>
            public override Status Serialize(StreamWriter writer, ISerializationContext context)
            {
                if (this.IsSet)
                {
                    writer.WriteLine(this.Contents.ToString());
                }
                else
                {
                    writer.WriteLine(Constants.NotSet);
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The to string.
            /// </summary>
            /// <returns>
            /// The to string.
            /// </returns>
            public override string ToString()
            {
                if (!this.IsSet)
                {
                    return Constants.NotSet;
                }

                return this.Contents.ToString();
            }

            /// <summary>
            /// The unset.
            /// </summary>
            public override void Unset()
            {
                if (!this.IsMandatory)
                {
                    this.contents = new int?();
                }
            }

            #endregion
        }

        /// <summary>
        /// The string.
        /// </summary>
        [Serializable]
        public class String : ConfigurationField
        {
            #region Constants and Fields

            /// <summary>
            /// The identity.
            /// </summary>
            private static readonly Identity Identity = Identity.Create(System.Reflection.MethodBase.GetCurrentMethod());

            /// <summary>
            /// The contents.
            /// </summary>
            private string contents;

            #endregion

            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="String"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            public String(bool mandatory)
                : base(mandatory)
            {
            }

            /// <summary>
            /// Initializes a new instance of the <see cref="String"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            /// <param name="s">
            /// The s.
            /// </param>
            public String(bool mandatory, string s)
                : base(mandatory)
            {
                this.contents = s;
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets or sets Contents.
            /// </summary>
            public override object Contents
            {
                get
                {
                    return this.contents;
                }

                set
                {
                    if (value is string)
                    {
                        this.contents = (string)value;
                    }
                    else if (this.IsMandatory)
                    {
                        throw new Exception("Field is mandatory");
                    }
                    else
                    {
                        this.Unset();
                    }
                }
            }

            /// <summary>
            /// Gets a value indicating whether IsSet.
            /// </summary>
            public override bool IsSet
            {
                get
                {
                    return this.Contents != null;
                }
            }

            #endregion

            #region Public Methods

            /// <summary>
            /// The de serialize.
            /// </summary>
            /// <param name="reader">
            /// The reader.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            public override Status DeSerialize(StreamReader reader, ISerializationContext context)
            {
                var valueString = reader.ReadLine();
                if (valueString == null)
                {
                    valueString = Constants.NotSet;
                }

                if (valueString.Equals(Constants.NotSet))
                {
                    this.Contents = null;
                }
                else
                {
                    this.Contents = valueString;
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The serialize.
            /// </summary>
            /// <param name="writer">
            /// The writer.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            /// <exception cref="NotImplementedException">
            /// </exception>
            public override Status Serialize(StreamWriter writer, ISerializationContext context)
            {
                if (this.IsSet)
                {
                    writer.WriteLine(this.Contents.ToString());
                }
                else
                {
                    writer.WriteLine(Constants.NotSet);
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The to string.
            /// </summary>
            /// <returns>
            /// The to string.
            /// </returns>
            public override string ToString()
            {
                if (!this.IsSet)
                {
                    return Constants.NotSet;
                }

                return this.Contents.ToString();
            }

            /// <summary>
            /// The unset.
            /// </summary>
            public override void Unset()
            {
                if (!this.IsMandatory)
                {
                    this.contents = null;
                }
            }

            #endregion
        }

        /// <summary>
        /// This class manages a table encapsulating a list of columns
        /// </summary>
        [Serializable]
        public class Table : BinaryConfigurationField
        {
            #region Constants and Fields

            /// <summary>
            /// The identity.
            /// </summary>
            private static readonly Identity Identity = Identity.Create(System.Reflection.MethodBase.GetCurrentMethod());

            /// <summary>
            /// The contents.
            /// </summary>
            private Framework.Table contents;

            #endregion

            #region Constructors and Destructors

            /// <summary>
            /// Initializes a new instance of the <see cref="Table"/> class.
            /// </summary>
            /// <param name="mandatory">
            /// The mandatory.
            /// </param>
            public Table(bool mandatory)
                : base(mandatory)
            {
                if (mandatory)
                {
                    this.contents = new Framework.Table();
                    this.Name = "Table.Empty";
                }
            }

            #endregion

            #region Properties

            /// <summary>
            /// Gets or sets Contents.
            /// </summary>
            public override object Contents
            {
                get
                {
                    return this.contents;
                }

                set
                {
                    if (value is Framework.Table)
                    {
                        this.contents = (Framework.Table)value;
                    }
                    else if (this.IsMandatory)
                    {
                        throw new Exception("Field is mandatory");
                    }
                    else
                    {
                        this.Unset();
                    }
                }
            }

            /// <summary>
            /// Gets a value indicating whether IsSet.
            /// </summary>
            public override bool IsSet
            {
                get
                {
                    return this.Contents != null;
                }
            }

            #endregion

            #region Public Methods

            /// <summary>
            /// The de serialize.
            /// </summary>
            /// <param name="reader">
            /// The reader.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            /// <exception cref="NotImplementedException">
            /// </exception>
            public override Status DeSerialize(StreamReader reader, ISerializationContext context)
            {
                var relativeTables = new List<string>();
                var fileName = reader.ReadLine();
                if (fileName.Equals(Constants.NotSet))
                {
                    return Status.Success(Identity);
                }

                if (context.WorkingDirectory != null)
                {
                    // Non null working directory means reading from file
                    context.BinaryContents[fileName] = System.IO.File.ReadAllBytes(string.Format(@"{0}\{1}", context.WorkingDirectory, fileName));
                }
                else
                {
                    // Null working directory means reading from database, thus context.BinaryContents[fileName] should be ready
                }

                this.Name = fileName;
                var tableContents = new Org.OpenTrader.Framework.Table();
                var mm = new MemoryStream(context.BinaryContents[fileName]);
                var sr = new StreamReader(mm);

                // Clear columns
                tableContents.Clear();

                string name;
                string[] names;
                var nbnames = 0;

                // get name line
                name = sr.ReadLine();

                // check name line
                if (name == null)
                {
                    return Status.Failure(Identity, "DeSerialize: name == null");
                }

                // set names
                names = name.Split(new char[] { '\t' });
                nbnames = names.Length;

                for (var i = 0; i < nbnames; i++)
                {
                    var c = new Framework.Table.Column(names[i]);
                    tableContents.Add(c);
                }

                // add data
                var currentLine = sr.ReadLine();
                while (currentLine != null)
                {
                    var currentLineColumns = currentLine.Split(new char[] { '\t' });
                    if (currentLineColumns.Length == nbnames)
                    {
                        for (var i = 0; i < nbnames; i++)
                        {
                            var cellContent = currentLineColumns[i];

                            // Special case (a relative table) stack it for future DeSerialize
                            if (cellContent.StartsWith("table:"))
                            {
                                // This is the subtable
                                var subTable = new Table(true);

                                // Create a stream were the name is stored for the subtable
                                var subTableName = cellContent.Replace("table:", string.Empty);
                                var mmm = new MemoryStream(ASCIIEncoding.ASCII.GetBytes(subTableName));
                                var srr = new StreamReader(mmm);

                                if (context.WorkingDirectory != null)
                                {
                                    // Add the binary content to the context
                                    try
                                    {
                                        var path = context.WorkingDirectory + @"\" + subTableName;
                                        context.BinaryContents[subTableName] = System.IO.File.ReadAllBytes(path);
                                    }
                                    catch (FileNotFoundException)
                                    {
                                        tableContents.Clear();
                                        return Status.Failure(
                                            Identity, 
                                            string.Format("DeSerialize: unable to handle sub table {0} file not found in {1}", subTableName, context.WorkingDirectory));
                                    }
                                }

                                // At this time we have 
                                // - StreamReader { "$subTableName" }
                                // - context.BinaryContents { ... , "$subTableName" => byte [] { ... }, ... }
                                // Everyting is ready to DeSerialize to subTable
                                var status = subTable.DeSerialize(srr, context);
                                if (status)
                                {
                                    // This cell content is not a string but a table
                                    tableContents[i].Add(new Framework.Table.Cell(subTable));
                                }
                                else
                                {
                                    tableContents.Clear();
                                    return Status.Failure(Identity, string.Format("DeSerialize: unable to handle sub table {0}", subTableName), status);
                                }
                            }
                            else
                            {
                                // This cell content is as string
                                tableContents[i].Add(new Framework.Table.Cell(cellContent));
                            }
                        }
                    }
                    else
                    {
                        tableContents.Clear();
                        var message = string.Format(
                            "DeSerialize: Input \"{0}\" hasn't the right number of columns (expected {1} got {2})", 
                            currentLine, 
                            nbnames, 
                            currentLineColumns.Length);

                        return Status.Failure(Identity, message);
                    }

                    currentLine = sr.ReadLine();
                }

                // All done
                this.Contents = tableContents;

                return Status.Success(Identity);
            }

            /// <summary>
            /// The serialize.
            /// </summary>
            /// <param name="writer">
            /// The writer.
            /// </param>
            /// <param name="context">
            /// The context.
            /// </param>
            /// <returns>
            /// </returns>
            /// <exception cref="NotImplementedException">
            /// </exception>
            public override Status Serialize(StreamWriter writer, ISerializationContext context)
            {
                if (this.IsSet)
                {
                    writer.WriteLine(this.Name);
                    var contents = this.Contents as Framework.Table;
                    var mm = new MemoryStream();
                    var sw = new StreamWriter(mm);
                    for (var j = 0; j < contents.ColCount; j++)
                    {
                        sw.Write(contents[j].Name);
                        if (j < contents.ColCount - 1)
                        {
                            sw.Write("\t");
                        }
                    }

                    sw.WriteLine();

                    for (var i = 0; i < contents.RowCount; i++)
                    {
                        for (var j = 0; j < contents.ColCount; j++)
                        {
                            var cell = contents[j][i];
                            if (cell.Content is Table)
                            {
                                var subTable = cell.Content as Table;
                                var mmm = new MemoryStream();
                                var sww = new StreamWriter(mmm);
                                var status = subTable.Serialize(sww, context);
                                if (!status)
                                {
                                    return Status.Failure(Identity, string.Format("Serialize: unable to handle sub table {0}", subTable.Name));
                                }

                                sw.Write("table:" + subTable.Name);
                            }
                            else
                            {
                                sw.Write(cell.Content.ToString());
                            }

                            if (j < contents.ColCount - 1)
                            {
                                sw.Write("\t");
                            }
                        }

                        sw.WriteLine();
                    }

                    sw.Flush();
                    var outarray = new byte[mm.Length];
                    Array.Copy(mm.GetBuffer(), outarray, mm.Length);
                    context.BinaryContents[this.Name] = outarray;
                }
                else
                {
                    writer.WriteLine(Constants.NotSet);
                }

                return Status.Success(Identity);
            }

            /// <summary>
            /// The to string.
            /// </summary>
            /// <returns>
            /// The to string.
            /// </returns>
            public override string ToString()
            {
                if (!this.IsSet)
                {
                    return Constants.NotSet;
                }

                var contents = this.Contents as Framework.Table;
                return string.Format("{0} (Table, rows={1} cols={2})", this.Name, contents.RowCount, contents.ColCount);
            }

            /// <summary>
            /// The unset.
            /// </summary>
            public override void Unset()
            {
                if (!this.IsMandatory)
                {
                    this.contents = null;
                }
            }

            #endregion
        }
    }
}